package com.gin.kotlin.no_gay_alliance.provider.ngajs

import com.fasterxml.jackson.databind.JavaType
import com.fasterxml.jackson.databind.type.TypeFactory
import com.gin.kotlin.no_gay_alliance.app.App
import com.gin.kotlin.no_gay_alliance.callback.SCallback
import com.gin.kotlin.no_gay_alliance.interceptor.LoggingInterceptor
import com.gin.kotlin.no_gay_alliance.interceptor.ResourceInterceptor
import com.gin.kotlin.no_gay_alliance.utils.FileCacheUtils
import com.gin.nga.api.ResourceApi
import com.gin.nga.main.NgaResource
import com.gin.retrofit.utils.JacksonUtils
import okhttp3.Cache
import java.io.File
import java.util.concurrent.TimeUnit

/**
 * 带缓存的静态资源提供者
 * @param R 源响应类型
 * @param D 缓存数据类型
 * @property expires 过期时长，默认6小时
 * @property TAG 日志TAG
 * @constructor
 */
abstract class AbstractNgaResourceProvider<R, D : Any>(
    private val javaType: JavaType,
    private val expires: Long = TimeUnit.HOURS.toSeconds(6)
) {
    @Suppress("PropertyName")
    protected val TAG: String = this::class.java.simpleName

    abstract val relativePath: String

    /**
     * 请求
     * @param ignoreCache Boolean
     * @param callback SCallback<D>
     */
    fun enqueue(ignoreCache: Boolean = false, callback: SCallback<D>? = null) {
        if (!ignoreCache) {
            val data: D? = FileCacheUtils.readCache(relativePath, expires, javaType)
            if (data != null) {
                callback?.onSuccess(data)
                return
            }
        }

        val resourceApi = NgaResource.Builder().also {
            it.clientBuilder
                .addInterceptor(LoggingInterceptor())
                .addInterceptor(ResourceInterceptor())
                // 配置缓存目录
                .cache(Cache(File(App.INSTANCE.cacheDir, "NGA_RESOURCE"), 50 * App.MB))
        }.build().api

        requestMethod(resourceApi).enqueue(object : retrofit2.Callback<R> {
            override fun onResponse(call: retrofit2.Call<R>, response: retrofit2.Response<R>) {
                val res = response.body()
                val data = transform(res)
                if (data != null) {
                    // 写入缓存
                    FileCacheUtils.writeCache(relativePath, data)
                    // 回调
                    callback?.onSuccess(data)
                } else onFailure(call, RuntimeException("响应为空"))
            }

            override fun onFailure(call: retrofit2.Call<R>, t: Throwable) {
                t.printStackTrace()
            }
        })
    }

    /**
     * 请求方法
     * @param resourceApi NgaApi
     * @return Call<NgaResponse<R>>
     */
    abstract fun requestMethod(resourceApi: ResourceApi): retrofit2.Call<R>


    /**
     * 将响应类型转换为缓存类型的方法
     * @param res R
     * @return D
     */
    abstract fun transform(res: R?): D?

    companion object {
        const val DIR = "NGA_RES"
        val TYPE_FACTORY: TypeFactory = JacksonUtils.MAPPER.typeFactory
    }


}